package DB;

import Beans.Deltaker;
import Beans.Klasse;
import Beans.Lop;
import Beans.Resultat;
import Verktoy.Filter;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.sql.*;
import java.util.ArrayList;
import java.util.Formatter;
import javax.annotation.Resource;
import javax.faces.context.FacesContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * Klasse som oppretter forbindelsene til databasen
 * @author Gruppe1
 */
public class DBehandler implements Serializable {

    private String dbNavn = "jdbc:derby://localhost:1527/waplj_prosjekt;user=waplj;password=waplj";
    private Connection forbindelse;
    private String databasedriver = "org.apache.derby.jdbc.ClientDriver";
    @Resource(name = "jdbc/personressurs")
    private DataSource ds;

    /**
     * Konstruktør som setter dbNavn
     * @param startDbNavn
     */
    public DBehandler(String startDbNavn) {
        dbNavn = startDbNavn;
    }

    /**
     * Konstruktør som oppretter en dataSource
     */
    public DBehandler() {
        try {
            Context ctx = new InitialContext();
            ds = (DataSource) ctx.lookup("java:comp/env/jdbc/personressurs");
        } catch (NamingException e) {
            System.err.println(e + " ******DBehandler****** konstruktør");
        }
    }

    private synchronized void åpneForbindelse() {
        try {
            if (ds == null) {
                throw new SQLException("Ingen data source!");
            }
            forbindelse = ds.getConnection();
        } catch (SQLException e) {
            Opprydder.skrivMelding(e, "Konstruktøren");
            Opprydder.lukkForbindelse(forbindelse);
        }
    }

    private synchronized void lukkForbindelse() {
        Opprydder.lukkForbindelse(forbindelse);
    }

    /**
     * Metode som registrer ny deltaker
     * @param deltaker
     * @return nummeret til deltakeren
     */
    public synchronized int registrerNyDeltaker(Deltaker deltaker) {
        PreparedStatement sqlRegNyDeltaker = null;
        int nr = -1;
        åpneForbindelse();
        boolean ok = false;
        try {
            /*
             * Transaksjon starter, en deltaker skal legges til
             */

            forbindelse.setAutoCommit(false);

            sqlRegNyDeltaker = forbindelse.prepareStatement("insert into deltaker (navn, adresse, epost, fodselsaar, delta_kjonn) VALUES(?, ?, ?, ?, ?)");

            /* Legger inn alt om deltakeren */
            sqlRegNyDeltaker.setString(1, (deltaker.getFnavn()) + " " + Filter.filtrer(deltaker.getEnavn()));
            sqlRegNyDeltaker.setString(2, (deltaker.getAdresse()));
            sqlRegNyDeltaker.setString(3, deltaker.getEpost());
            sqlRegNyDeltaker.setInt(4, deltaker.getFaar());
            sqlRegNyDeltaker.setString(5, deltaker.getKjonn());
            sqlRegNyDeltaker.executeUpdate();

            sqlRegNyDeltaker = forbindelse.prepareStatement("insert into bruker VALUES(?, ?)");

            /* Legger inn alt om deltakeren */
            sqlRegNyDeltaker.setString(1, deltaker.getEpost());
            sqlRegNyDeltaker.setString(2, deltaker.getPassord1());
            sqlRegNyDeltaker.executeUpdate();

            sqlRegNyDeltaker = forbindelse.prepareStatement("insert into rolle VALUES(?, ?)");

            /* Legger inn alt om deltakeren */
            sqlRegNyDeltaker.setString(1, deltaker.getEpost());
            sqlRegNyDeltaker.setString(2, "bruker");
            sqlRegNyDeltaker.executeUpdate();



            forbindelse.commit();

            ok = true;
        } catch (SQLException e) {
            Opprydder.rullTilbake(forbindelse);
            String sqlStatus = e.getSQLState().trim();
            String statusklasse = sqlStatus.substring(0, 2);
            if (statusklasse.equals("23")) { // standard kode for "integrity constraint violation"
                ok = true;
            } else {
                Opprydder.skrivMelding(e, "DBehandler.regNyDeltaker()");
            }
        } finally {
            Opprydder.settAutoCommit(forbindelse);
            Opprydder.lukkSetning(sqlRegNyDeltaker);
        }

        lukkForbindelse();
        nr = hentDeltakerNr(deltaker);
        return nr;
    }

    private synchronized int hentDeltakerNr(Deltaker delta) {
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        int nr = -1;
        try {
            String setning = "SELECT * FROM deltaker WHERE epost = ?";
            stm = forbindelse.prepareStatement(setning);
            stm.setString(1, delta.getEpost());
            res = stm.executeQuery();
            while (res.next()) {
                nr = res.getInt("deltaker_id");
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentDeltakerNr() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return nr;
    }

    /**
     * Metode som registrerer nytt løp
     * @param lop
     * @return siste løp nummer
     */
    public synchronized int registrerNyttLop(Lop lop) {
        int nr = -1;
        if (!sjekkLop(lop)) {
            return -2;
        }
        åpneForbindelse();
        ResultSet res = null;
        PreparedStatement sqlRegNyttLop = null;
        try {
            forbindelse.setAutoCommit(false);
            sqlRegNyttLop = forbindelse.prepareStatement("insert into Lop (lop_navn, dato, distanse, beskrivelse) values(?, ?, ?, ?)");
            sqlRegNyttLop.setString(1, lop.getLopnavn());
            sqlRegNyttLop.setDate(2, lop.getDate());
            sqlRegNyttLop.setDouble(3, lop.getDistanse());
            sqlRegNyttLop.setString(4, (lop.getBeskrivelse()));
            sqlRegNyttLop.executeUpdate();
            forbindelse.commit();
        } catch (SQLException e) {
            Opprydder.rullTilbake(forbindelse);
            Opprydder.skrivMelding(e, "DBehandler.regNyttLop()");
            String sqlStatus = e.getSQLState().trim();
            String statusklasse = sqlStatus.substring(0, 2);
            if (statusklasse.equals("23")) { // standard kode for "integrity constraint violation"
            }
        } finally {
            Opprydder.lukkResSet(res);
            Opprydder.lukkSetning(sqlRegNyttLop);
            Opprydder.settAutoCommit(forbindelse);
        }
        lukkForbindelse();
        nr = hentSisteLopNr();
        return nr;
    }

    private synchronized boolean sjekkLop(Lop lop) {
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        boolean ok = true;
        try {
            String setning = "SELECT * FROM lop";
            stm = forbindelse.prepareStatement(setning);
            res = stm.executeQuery();
            while (res.next()) {
                String navn = res.getString("lop_navn");
                Date dato = res.getDate("dato");
                Double distanse = res.getDouble("distanse");
                String beskrivelse = res.getString("beskrivelse");
                if (ok && navn.equals(lop.getLopnavn()) && dato.equals(lop.getDate()) && distanse == lop.getDistanse() && beskrivelse.equals(lop.getBeskrivelse())) {
                    ok = false;
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.SjekkLop() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return ok;
    }

    private synchronized int hentSisteLopNr() {

        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        int nr = -1;
        try {
            String str = "SELECT max(lop_id) FROM lop";
            stm = forbindelse.prepareStatement(str);
            res = stm.executeQuery();
            while (res.next()) {
                nr = res.getInt(1);
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentSisteLopNr() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return nr;
    }

    /**
     * Metode som registrererResultat 
     * @param startnr
     * @param lop_id
     * @param tid
     * @return true hvis registreringen gikk bra, false hvis ikke
     */
    public synchronized boolean registrerResultat(int startnr, int lop_id, Time tid) {

        boolean ok = false;
        åpneForbindelse();
        ResultSet res = null;
        PreparedStatement sqlRegRes = null;
        try {
            forbindelse.setAutoCommit(false);
            sqlRegRes = forbindelse.prepareStatement("UPDATE resultat SET tid = ? where startnr = ? and lop_id = ?");
            sqlRegRes.setTime(1, tid);
            sqlRegRes.setInt(2, startnr);
            sqlRegRes.setInt(3, lop_id);
            sqlRegRes.executeUpdate();
            forbindelse.commit();
            ok = true;

        } catch (SQLException e) {
            Opprydder.skrivMelding(e, "DBehandler.regResultat()");
        } finally {
            Opprydder.lukkResSet(res);
            Opprydder.lukkSetning(sqlRegRes);
            Opprydder.settAutoCommit(forbindelse);
        }
        lukkForbindelse();
        return ok;
    }

    /**
     * Metode som sjekker deltaker på løp
     * @param deltaker_id
     * @param lop_id
     * @return false hvis brukeren finnes fra før på løpet
     */
    public synchronized boolean sjekkDeltakerPaaLop(int deltaker_id, int lop_id) {
        PreparedStatement stm = null;
        ResultSet res = null;
        åpneForbindelse();
        boolean ok = true;
        try {
            String str = "SELECT * FROM resultat";
            stm = forbindelse.prepareStatement(str);
            res = stm.executeQuery();
            while (res.next()) {
                if (ok && res.getInt("deltaker_id") == deltaker_id && res.getInt("lop_id") == lop_id) {
                    ok = false;
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.sjekkDeltakerPaaLop() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return ok;
    }

    /**
     * Metode som finner resultat på et løp
     * @param lop_id
     * @param klasseForst
     * @param rekkefolge
     * @return en sortert rekkefølge av resultatene
     */
    public synchronized ArrayList<Resultat> finnResultatLop(int lop_id, boolean klasseForst, boolean rekkefolge) {
        return sortert(lop_id, klasseForst, rekkefolge);
    }

    /**
     * Metode som sorterer resultatene på et løp, enten etter tid eller etter klasse
     * @param lop_id
     * @param klasseForst
     * @param rekkefolge
     * @return en arrayListe med objekt av typen Resultat sortert etter tid/klasse
     */
    public synchronized ArrayList<Resultat> sortert(int lop_id, boolean klasseForst, boolean rekkefolge) {
        ArrayList<Resultat> alleResultat = new ArrayList<Resultat>();
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String tekst = "";
            if (klasseForst) {
                if (rekkefolge) {
                    tekst = "ORDER BY KLASSE.KJONN asc, KLASSE.ALDERSINNDELING asc, RESULTAT.TID ASC";
                } else {
                    tekst = "ORDER BY KLASSE.KJONN desc, KLASSE.ALDERSINNDELING desc, RESULTAT.TID desc";
                }
            } else {
                if (rekkefolge) {
                    tekst = "ORDER BY RESULTAT.TID ASC";
                } else {
                    tekst = "ORDER BY RESULTAT.TID desc";
                }
            }
            String sql = lop_id == 0
                    ? "SELECT * FROM RESULTAT JOIN DELTAKER on (RESULTAT.DELTAKER_ID=DELTAKER.DELTAKER_ID) JOIN LOP ON (RESULTAT.LOP_ID = LOP.LOP_ID) JOIN KLASSE ON (RESULTAT.KLASSE_ID = KLASSE.KLASSE_ID) " + tekst
                    : "SELECT * FROM RESULTAT JOIN DELTAKER on (RESULTAT.DELTAKER_ID=DELTAKER.DELTAKER_ID) JOIN LOP ON (RESULTAT.LOP_ID = LOP.LOP_ID) JOIN KLASSE ON (RESULTAT.KLASSE_ID = KLASSE.KLASSE_ID) WHERE RESULTAT.LOP_ID = ? " + tekst;
            stm = forbindelse.prepareStatement(sql);
            if(lop_id!=0)
                stm.setInt(1, lop_id);
            res = stm.executeQuery();
            while (res.next()) {
                String[] navn = res.getString("navn").split(" ");
                String etterNavn = navn[navn.length - 1];
                String fornavn = "";
                for (int i = 0; i < navn.length - 1; i++) {
                    fornavn += navn[i] + " ";
                }
                alleResultat.add(
                        new Resultat(
                        new Deltaker(fornavn, etterNavn, res.getString("epost"), res.getString("adresse"), res.getInt("fodselsaar"), res.getString("kjonn"), res.getInt("deltaker_id")),
                        new Klasse(res.getInt("klasse_id"), res.getString("aldersinndeling"), res.getString("kjonn")),
                        new Lop(res.getInt("lop_id"), res.getString("lop_navn"), res.getDate("dato"), res.getDouble("distanse"), res.getString("beskrivelse")),
                        res.getInt("startnr"),
                        res.getTime("tid")));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.sorter() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return alleResultat;
    }

    /**
     * Metode som finner gjennomsnittstiden på et løp
     * @param lop_id
     * @return gjennomsnittstiden
     */
    public synchronized Time finnGjennomsnittLop(int lop_id) {
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement setning = null;
        long tid = 0L;
        int teller = 0;
        try {

            String stm = lop_id == 0 ? "SELECT TID FROM RESULTAT WHERE TID > '00:00:00'" : "SELECT TID FROM RESULTAT WHERE LOP_ID = " + lop_id + " AND TID > '00:00:00'";
            setning = forbindelse.prepareStatement(stm);
            res = setning.executeQuery();
            while (res.next()) {
                Time tiden = res.getTime(1);
                tid += tiden.getTime();
                teller++;
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnGjennomsnittLop(): " + e);
        } finally {
            Opprydder.lukkSetning(setning);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return teller != 0 ? new Time(tid / teller) : new Time(tid);
    }

    /**
     * Metide som registrerer en deltaker på et løp
     * @param lop_id
     * @param deltaker_id
     * @param klasse_id
     * @return startnummer til deltakeren
     */
    public synchronized int registrerDeltakerPaaLop(int lop_id, int deltaker_id, int klasse_id) {
        if (!sjekkDeltakerPaaLop(deltaker_id, lop_id)) {
            return -2;
        }
        int nr = -1;
        åpneForbindelse();
        ResultSet res = null;
        PreparedStatement sqlRegRes = null;
        try {
            sqlRegRes = forbindelse.prepareStatement("insert into Resultat values(?, null, ?, ?, ?)");
            nr = hentNesteStartNr(lop_id);
            sqlRegRes.setInt(1, nr);
            sqlRegRes.setInt(2, deltaker_id);
            sqlRegRes.setInt(3, lop_id);
            sqlRegRes.setInt(4, klasse_id);

            sqlRegRes.executeUpdate();
        } catch (SQLException e) {
            Opprydder.skrivMelding(e, "DBehandler.regDeltakerPaaLop()");
        } catch (Exception e) {
            Opprydder.skrivMelding(e, "regDeltakerPaaLop() - kan ikke registrere samme deltaker på samme løp!");
        } finally {
            Opprydder.lukkResSet(res);
            Opprydder.lukkSetning(sqlRegRes);
        }
        lukkForbindelse();
        return nr;
    }
    /**
     * Henter alle retultat registrert på en deltaker
     * @return ArrayList med Ojekt av typen Resultat
     */
    public synchronized ArrayList<Resultat> hentResultatDeltaker() {
        ArrayList<Resultat> resultat = new ArrayList<Resultat>();
        FacesContext context = FacesContext.getCurrentInstance();
        Principal p = context.getExternalContext().getUserPrincipal();
        String epost = p.getName();
        ResultSet r = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            int delta_id = finnDeltakerIdEpost(epost);
            String sql = "SELECT * FROM resultat WHERE deltaker_id = ?"; 
            stm = forbindelse.prepareStatement(sql);
            stm.setInt(1, delta_id);
            r = stm.executeQuery();
            while (r.next()) {
                String[] navn = r.getString("navn").split(" ");
                String etternavn = navn[navn.length - 1];
                String fornavn = "";
                for (int i = 0; i < navn.length - 1; i++) {
                    fornavn += navn[i] + " ";
                }
                Deltaker d = new Deltaker(fornavn, etternavn, r.getString("epost"), r.getString("adresse"), r.getInt("fodselsaar"), r.getString("delta_kjonn"), r.getInt("deltaker_id"));

                Klasse k = new Klasse(r.getInt("klasse_id"), r.getString("aldersinndeling"), r.getString("kjonn"));

                Lop l = new Lop(r.getInt("lop_id"), r.getString("lop_navn"), r.getDate("dato"), r.getDouble("distanse"), r.getString("beskrivelse"));

                Time tid = r.getTime("tid");
                resultat.add(new Resultat(d, k, l, r.getInt("startnr"), tid));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentResultatDeltaker() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(r);
        }
        lukkForbindelse();
        return resultat;
    }

    private synchronized int hentNesteStartNr(int nr) {
        PreparedStatement setning = null;
        ResultSet res = null;
        åpneForbindelse();
        int nre = 0;
        try {
            String stm = "SELECT max(startnr) FROM resultat WHERE lop_id = ?";
            setning = forbindelse.prepareStatement(stm);
            setning.setInt(1, nr);
            res = setning.executeQuery();
            while (res.next()) {
                nre = res.getInt(1);
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentNesteStartNr() " + e);
        } finally {
            Opprydder.lukkSetning(setning);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return nre + 1;
    }

    /**
     * Metode som henter ut alle løp fra db
     * @return arrayList med alle løpene
     */
    public synchronized ArrayList<Lop> finnAlleLop() {
        ArrayList<Lop> alleLop = new ArrayList<Lop>();
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM lop";
            stm = forbindelse.prepareStatement(sql);
            res = stm.executeQuery();
            while (res.next()) {
                alleLop.add(new Lop(res.getInt("lop_id"), res.getString("lop_navn"), res.getDate("dato"), res.getDouble("distanse"), res.getString("beskrivelse")));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnAlleLop(): " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return alleLop;
    }

    /**
     * Metode som henter ut alle løp fra db som en gitt deltaker ikke er med i.
     * @param deltaker_id hvilken deltaker det gjelder
     * @return arrayList med alle løpene som denne deltakeren ikke er med på.
     */
    public synchronized ArrayList<Lop> finnBrukerLop(int deltaker_id) {
        ArrayList<Lop> alleLop = new ArrayList<Lop>();
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            /*Brukes for å kun få tilgang til de løp du ikke er meldt opp på*/
            String stm2 = "Select distinct l.lop_id, lop_navn, dato, distanse, beskrivelse "
                    + "from lop l "
                    + "left outer join resultat r "
                    + "on(l.lop_id = r.lop_id) "
                    + "where l.lop_id "
                    + "not in ("
                    + "select l2.lop_id "
                    + "from lop l2 "
                    + "left outer join resultat r2 "
                    + "on(l2.lop_id = r2.lop_id) "
                    + "where DELTAKER_ID = ?)";
            
            stm = forbindelse.prepareStatement(stm2);
            stm.setInt(1, deltaker_id);
            res = stm.executeQuery();
            while (res.next()) {
                alleLop.add(new Lop(res.getInt("lop_id"), res.getString("lop_navn"), res.getDate("dato"), res.getDouble("distanse"), res.getString("beskrivelse")));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnBrukerLop(): " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return alleLop;
    }

    /**
     * Sletter er resultat fra databasen
     * @param r Objekt av typen Reultat som skal slettes
     * @return true dersom slettingen gikk bra, false dersom dette Resultat-objektet ikke har atributtet "deleted" = true eller dersom dette objektet ikke finnes i databasen.
     */
    public synchronized boolean slettResultat(Resultat r) {
        if (!r.isDeleted()) {
            return false;
        }
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement setning = null;
        boolean ok = false;
        try {
            String stm = "DELETE FROM WAPLJ.RESULTAT WHERE DELTAKER_ID = ? AND KLASSE_ID = ? AND LOP_ID = ?;";
            setning = forbindelse.prepareStatement(stm);
            setning.setInt(1, r.getDelta().getDeltaker_id());
            setning.setInt(2, r.getKlasse().getId());
            setning.setInt(3, r.getLop().getLop_id());
            ok = setning.executeUpdate() == 1;
        } catch (SQLException e) {
            System.err.println("DBehandler.slettResultat(): " + e);
        } finally {
            Opprydder.lukkSetning(setning);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return ok;
    }

    /**
     * Metode som henter alle deltakere
     * @return arrayList med alle deltakere
     */
    public synchronized ArrayList<Deltaker> hentAlleDeltakere() {
        ArrayList<Deltaker> alleDeltakere = new ArrayList<Deltaker>();

        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;

        try {
            String sql = "SELECT * FROM deltaker";
            stm = forbindelse.prepareStatement(sql);
            res = stm.executeQuery();
            while (res.next()) {
                if (res.getString("navn") != null) {
                    String[] navn = res.getString("navn").split(" ");
                    String etterNavn = navn[navn.length - 1];
                    String fornavn = "";
                    for (int i = 0; i < navn.length - 1; i++) {
                        fornavn += navn[i] + " ";
                    }
                    alleDeltakere.add(new Deltaker(fornavn.trim(), etterNavn, res.getString("epost"), res.getString("adresse"), res.getInt("fodselsaar"), res.getString("delta_kjonn"), res.getInt("deltaker_id")));
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAlleDeltakere()1: " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.hentAlleDeltakere()2: " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return alleDeltakere;
    }

    /**
     * Metode som henter ut en deltaker
     * @return enten en arrayList med alle deltakere hvis sys er innlogget, hvis ikke hentes kun brukerens opplysninger
     */
    public synchronized ArrayList<Deltaker> hentEnDeltaker() {
        ArrayList<Deltaker> alleDeltakere = new ArrayList<Deltaker>();
        FacesContext context = FacesContext.getCurrentInstance();
        Principal p = context.getExternalContext().getUserPrincipal();
        String epost = p.getName();

        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;

        try {

            String sql = epost.equals("sys") ? "SELECT * FROM deltaker order by navn asc" : "SELECT * FROM deltaker where epost = ?";
            stm = forbindelse.prepareStatement(sql);
            if(!epost.equals("sys"))
                stm.setString(1, epost);
            res = stm.executeQuery();
            while (res.next()) {
                if (res.getString("navn") != null) {
                    String[] navn = res.getString("navn").split(" ");
                    String etterNavn = navn[navn.length - 1];
                    String fornavn = "";
                    for (int i = 0; i < navn.length - 1; i++) {
                        fornavn += navn[i] + " ";
                    }
                    alleDeltakere.add(new Deltaker(fornavn.trim(), etterNavn, res.getString("epost"), res.getString("adresse"), res.getInt("fodselsaar"), res.getString("delta_kjonn"), res.getInt("deltaker_id")));
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentEnDeltaker(): " + e);
        } catch (Exception ee) {
            System.err.println(ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();

        return alleDeltakere;
    }

    /**
     * Metode som finner alle deltakere på et løp
     * @param lop_id
     * @return arrayList med alle deltakere som er registrert på et løp
     */
    public synchronized ArrayList<Deltaker> finnAlleDeltakereEtLop(int lop_id) {
        ArrayList<Deltaker> alleDeltakere = new ArrayList<Deltaker>();

        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement setning = null;
        try {
            String stm = "SELECT resultat.deltaker_id, navn, adresse, epost, FODSELSAAR, delta_kjonn FROM DELTAKER, RESULTAT WHERE DELTAKER.DELTAKER_ID = RESULTAT.DELTAKER_ID AND LOP_ID = ?";
            setning = forbindelse.prepareStatement(stm);
            setning.setInt(1, lop_id);
            res = setning.executeQuery(stm);

            while (res.next()) {
                if (res.getString("navn") != null) {
                    String[] navn = res.getString("navn").split(" ");
                    String etterNavn = navn[navn.length - 1];
                    String fornavn = "";
                    for (int i = 0; i < navn.length - 1; i++) {
                        fornavn += navn[i] + " ";
                    }
                    alleDeltakere.add(new Deltaker(fornavn.trim(), etterNavn, res.getString("epost"), res.getString("adresse"), res.getInt("fodselsaar"), res.getString("delta_kjonn"), res.getInt("deltaker_id")));
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAlleDeltakereEtLop(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.hentAlleDeltakereEtLop(): " + ee);
        } finally {
            Opprydder.lukkSetning(setning);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();

        return alleDeltakere;
    }

    /**
     * Metode som henter ut alle klassene med klasse_id, aldersinndeling og kjønn
     * @return arrayList med alle klassene i
     */
    public synchronized ArrayList<Klasse> hentAlleKlasser() {
        ArrayList<Klasse> alleKlasser = new ArrayList<Klasse>();

        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM klasse";
            stm = forbindelse.prepareStatement(sql);
            res = stm.executeQuery();

            while (res.next()) {
                alleKlasser.add(new Klasse(res.getInt("klasse_id"), res.getString("aldersinndeling"), res.getString("kjonn")));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAlleKlasser(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.hentAlleKlasser(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();

        return alleKlasser;
    }

    /**
     * Metode som henter ut alle resultat
     * @return arrayList med alle resultat til alle løp
     */
    public synchronized ArrayList<Resultat> hentAlleResultat() {
        ArrayList<Resultat> alleResultat = new ArrayList<Resultat>();
        ResultSet r = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM resultat r, lop l, deltaker d, klasse k "
                    + "where "
                    + "r.deltaker_id = d.deltaker_id and "
                    + "r.lop_id = l.lop_id and "
                    + "r.klasse_id = k.klasse_id";
            stm = forbindelse.prepareStatement(sql);
            r = stm.executeQuery();
            while (r.next()) {

                String[] navn = r.getString("navn").split(" ");
                String etternavn = navn[navn.length - 1];
                String fornavn = "";
                for (int i = 0; i < navn.length - 1; i++) {
                    fornavn += navn[i] + " ";
                }
                Deltaker d = new Deltaker(fornavn, etternavn, r.getString("epost"), r.getString("adresse"), r.getInt("fodselsaar"), r.getString("delta_kjonn"), r.getInt("deltaker_id"));

                Klasse k = new Klasse(r.getInt("klasse_id"), r.getString("aldersinndeling"), r.getString("kjonn"));

                Lop l = new Lop(r.getInt("lop_id"), r.getString("lop_navn"), r.getDate("dato"), r.getDouble("distanse"), r.getString("beskrivelse"));

                Time tid = r.getTime("tid");
                alleResultat.add(new Resultat(d, k, l, r.getInt("startnr"), tid));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAlleResultat() " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(r);
        }
        lukkForbindelse();

        return alleResultat;
    }

    /**
     * Metode som henter ut et resultat på et løp for en bruker
     * @param start_nr
     * @param lop_id
     * @return et resultat med deltaker, klasse, løp og startnr
     */
    public synchronized Resultat hentAlleResultat(int start_nr, int lop_id) {
        Resultat resultat = null;
        ResultSet r = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM resultat r, lop l, deltaker d, klasse k "
                    + "where "
                    + "r.deltaker_id = d.deltaker_id and "
                    + "r.lop_id = l.lop_id and "
                    + "r.klasse_id = k.klasse_id and "
                    + "r.lop_id = ? and "
                    + "r.startnr =?";
            stm = forbindelse.prepareStatement(sql);
            stm.setInt(1, lop_id);
            stm.setInt(2, start_nr);
            r = stm.executeQuery();
            while (r.next()) {
                String[] navn = r.getString("navn").split(" ");
                String etternavn = navn[navn.length - 1];
                String fornavn = "";
                for (int i = 0; i < navn.length - 1; i++) {
                    fornavn += navn[i] + " ";
                }
                Deltaker d = new Deltaker(fornavn, etternavn, r.getString("epost"), r.getString("adresse"), r.getInt("fodselsaar"), r.getString("delta_kjonn"), r.getInt("deltaker_id"));
                Klasse k = new Klasse(r.getInt("klasse_id"), r.getString("aldersinndeling"), r.getString("kjonn"));
                Lop l = new Lop(r.getInt("lop_id"), r.getString("lop_navn"), r.getDate("dato"), r.getDouble("distanse"), r.getString("beskrivelse"));
                resultat = new Resultat(d, k, l, r.getInt("startnr"));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAlleResultat(): " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(r);
        }
        lukkForbindelse();
        return resultat;
    }

    /**
     * Metode som finner en deltaker 
     * @param lopNr
     * @param startNr
     * @return et deltaker object 
     */
    public synchronized Deltaker finnDeltaker(int lopNr, int startNr) {
        Deltaker d = null;
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM resultat r, deltaker d "
                    + "WHERE d.deltaker_id = r.deltaker_id "
                    + "AND lop_id = ?"
                    + "AND startnr = ?";
            stm = forbindelse.prepareStatement(sql);
            stm.setInt(1, lopNr);
            stm.setInt(2, startNr);
            res = stm.executeQuery();

            while (res.next()) {
                if (res.getString("navn") != null) {
                    String[] navn = res.getString("navn").split(" ");
                    String etterNavn = navn[navn.length - 1];
                    String fornavn = "";
                    for (int i = 0; i < navn.length - 1; i++) {
                        fornavn += navn[i] + " ";
                    }
                    d = new Deltaker(fornavn.trim(), etterNavn, res.getString("epost"), res.getString("adresse"), res.getInt("fodselsaar"), res.getString("delta_kjonn"), res.getInt("deltaker_id"));
                }
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnDeltaker(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.finnDeltaker(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return d;
    }

    /**
     * Metode som finner et løp
     * @param lopNr
     * @return et lop object
     */
    public synchronized Lop finnLop(int lopNr) {
        Lop l = null;
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM lop WHERE lop_id = ?";
            stm = forbindelse.prepareStatement(sql);
            stm.setInt(1, lopNr);
            res = stm.executeQuery();
            while (res.next()) {
                l = new Lop(lopNr, res.getString("lop_navn"), res.getDate("dato"), res.getDouble("distanse"), res.getString("beskrivelse"));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnLop(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.finnLop(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return l;
    }

    /**
     * Metode som finner en klasse
     * @param lopNr
     * @param startNr
     * @return et klasse object
     */
    public synchronized Klasse finnKlasse(int lopNr, int startNr) {
        Klasse k = null;
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT k.* FROM resultat r, klasse k "
                    + "WHERE r.klasse_id = k.klasse_id "
                    + "and lop_id = ?"
                    + "and startnr = ?";
            stm = forbindelse.prepareStatement(sql);
            stm.setInt(1, lopNr);
            stm.setInt(2, startNr);
            res = stm.executeQuery();
            while (res.next()) {
                k = new Klasse(res.getInt("klasse_id"), res.getString("aldersinndeling"), res.getString("kjonn"));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnKlasse(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.finnKlasse(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return k;
    }

    /**
     * Metode som kaller på hentAlleResultat lenger opp
     * @see DBehandler.hentAlleResultat
     * @param start_nr
     * @param lop_id
     * @return et resultat med deltaker, klasse, løp og startnr
     */
    public synchronized Resultat hentResultat(int start_nr, int lop_id) {
        return hentAlleResultat(start_nr, lop_id);
    }

    /**
     * Metode som lagrer beskrivelsen av et felt samt hva som står i feltet
     * @see RegistreringsBean.saveForrord()
     * @param beskrivelse
     * @param infofelt
     */
    public synchronized void lagreAdminData(String beskrivelse, String infofelt) {
        åpneForbindelse();
        ResultSet res = null;
        PreparedStatement sqlRegNyttLop = null;
        try {
            forbindelse.setAutoCommit(false);
            sqlRegNyttLop = forbindelse.prepareStatement("update ADMINDATA set infofelt = ? where beskrivelse = ?");
            sqlRegNyttLop.setString(1, infofelt);
            sqlRegNyttLop.setString(2, beskrivelse);
            sqlRegNyttLop.executeUpdate();
            forbindelse.commit();
        } catch (SQLException e) {
            Opprydder.rullTilbake(forbindelse);
            Opprydder.skrivMelding(e, "lagreAdminData()");
            String sqlStatus = e.getSQLState().trim();
            String statusklasse = sqlStatus.substring(0, 2);
            if (statusklasse.equals("23")) { // standard kode for "integrity constraint violation"
                //finnes fra før!
            }
        } finally {
            Opprydder.lukkResSet(res);
            Opprydder.lukkSetning(sqlRegNyttLop);
            Opprydder.settAutoCommit(forbindelse);
        }
        lukkForbindelse();
    }

    /**
     * Metode som henter ut det som står i infofeltet 
     * @param beskrivelse
     * @return en string fra tabellen admindata i db
     */
    public synchronized String hentAdminData(String beskrivelse) {
        String resultat = null;
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT INFOFELT FROM ADMINDATA WHERE BESKRIVELSE = ?";
            stm = forbindelse.prepareStatement(sql);
            stm.setString(1, beskrivelse);
            res = stm.executeQuery();
            while (res.next()) {
                resultat = res.getString("infofelt");
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.hentAdmindata(): " + e);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return resultat;
    }

    /**
     * Metode som genererer en MD5 hash fra en string
     * @param strToBeEncrypted
     * @return en kryptert string
     */
    public static String getMD5HashVal(String strToBeEncrypted) {
        String encryptedString = null;
        byte[] bytesToBeEncrypted;
        try {
            bytesToBeEncrypted = strToBeEncrypted.getBytes("UTF-8");
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] theDigest = md.digest(bytesToBeEncrypted);
            Formatter formatter = new Formatter();
            for (byte b : theDigest) {
                formatter.format("%02x", b);
            }
            encryptedString = formatter.toString().toLowerCase();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return encryptedString;
    }

    /**
     * Metode som oppdaterer en deltaker
     * @param r
     */
    public synchronized void updateDeltaker(Deltaker r) {
        åpneForbindelse();
        PreparedStatement setning = null;
        try {
            String stm = "update deltaker set navn = ?, adresse = ?, epost = ?, fodselsaar = ?, delta_kjonn = ? where deltaker_id = ?";
            setning = forbindelse.prepareStatement(stm);
            setning.setString(1, r.getFnavn() + " " + r.getEnavn());
            setning.setString(2, r.getAdresse());
            setning.setString(3, r.getEpost());
            setning.setInt(4, r.getFaar());
            setning.setString(5, r.getKjonn());
            setning.setInt(6, r.getDeltaker_id());
            setning.executeUpdate();
        } catch (SQLException e) {
            System.err.println("DBehandler.updateDeltkater(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.updateDeltkater(): " + ee);
        } finally {
            Opprydder.lukkSetning(setning);
        }
        lukkForbindelse();
    }

    /**
     * Metode som identifiserer en klasse
     * @param alder
     * @param kjonn
     * @return et klasseobject
     */
    public synchronized Klasse identifiserKlasse(String alder, String kjonn) {
        Klasse k = null;
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        try {
            String sql = "SELECT * FROM klasse k "
                    + "WHERE aldersinndeling = ?"
                    + "and kjonn = ?";
            stm = forbindelse.prepareStatement(sql);
            stm.setString(1, alder);
            stm.setString(2, kjonn);
            res = stm.executeQuery();
            while (res.next()) {
                k = new Klasse(res.getInt("klasse_id"), res.getString("aldersinndeling"), res.getString("kjonn"));
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.identifiserKlasse(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.identifiserKlasse(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return k;
    }

    /**
     * Metode som sjekker om bruker 
     * @param epost
     * @param gmlPassord
     * @param p1
     * @return true om passordet blir oppdatert
     */
    public synchronized boolean sjekkBruker(String epost, String gmlPassord, String p1) {
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement setn = null;
        int teller = 0;
        try {
            String stm2 = "SELECT * FROM bruker b WHERE b.bruker = ? and b.passord = ?";
            setn = forbindelse.prepareStatement(stm2);
            setn.setString(1, epost);
            setn.setString(2, (gmlPassord));
            res = setn.executeQuery();
            while (res.next()) {
                teller += 1;
            }
            if (teller == 1) {
                String stm3 = "update bruker b set passord = ? where b.bruker = ?";
                setn = forbindelse.prepareStatement(stm3);
                setn.setString(1, (p1));
                setn.setString(2, epost);
                teller = setn.executeUpdate();
            }
            if (teller != 1) {
                System.err.println("DBehandler.sjekkBruker(): Mer enn en kolonne oppdatert! O.o");
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.sjekkBruker(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.sjekkBruker(): " + ee);
        } finally {
            Opprydder.lukkSetning(setn);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return teller == 1;
    }
    /**
     * Metode som finner deltaker_id til en deltaker med en gitt epost
     * @param epost Eposten til deltakeren
     * @return deltaker_iden i form av en int
     */
    public synchronized int finnDeltakerIdEpost(String epost) {
        ResultSet res = null;
        åpneForbindelse();
        PreparedStatement stm = null;
        int delta_id = -1;
        try {
            String sql = epost.equals("sys") ? "select * from deltaker" : "SELECT deltaker_id FROM deltaker d WHERE epost = ?";
            
            stm = forbindelse.prepareStatement(sql);
            if (!epost.equals("sys")) stm.setString(1, epost);
            res = stm.executeQuery();
            while (res.next()) {
                delta_id = res.getInt(1);
            }
        } catch (SQLException e) {
            System.err.println("DBehandler.finnDeltakerIdEpost(): " + e);
        } catch (Exception ee) {
            System.err.println("DBehandler.finnDeltakerIdEpost(): " + ee);
        } finally {
            Opprydder.lukkSetning(stm);
            Opprydder.lukkResSet(res);
        }
        lukkForbindelse();
        return delta_id;
    }
}
